#include "device.h"
//昂瑞微的驱动库API
#include "rwip_config.h" // RW SW configuration
#include "peripheral.h"
#include "eeprom.h"

#define ee_log(format, ...)                 //__OSAL_LOG("[eeprom.c] " format, ##__VA_ARGS__)
#define __ee_log(format, ...)               __OSAL_LOG(format, ##__VA_ARGS__)

#define EE_FLASH_START_ADDR                 FLASH_ADDR_EEPROM //flash起始地址
#define EE_FLASH_SECTOR_SIZE                4096       //flash扇区大小
#define EE_FLASH_SECTOR_QTY                 9          //flash扇区数量

#define EE_SECTOR_DATA_BLOCK_SIZE           32         //扇区内每个数据块的大小
#define EE_SECTOR_DATA_BLOCK_QTY            64         //扇区内存储的有效数据块的数量
#define EE_SECTOR_ADMIN_DATA_BLOCK_ADDR     (EE_FLASH_SECTOR_SIZE - EE_SECTOR_DATA_BLOCK_SIZE)//扇区内管理块的地址（扇区内最后一个块）


static uint8_t debug_enable = 0;
static uint8_t free_sector = 0xFF;  //空闲扇区
static uint16_t addr_index[(EE_FLASH_SECTOR_QTY - 1) * EE_SECTOR_DATA_BLOCK_QTY];//地址索引表

static const unsigned char crc_table[] =
{
    0x00,0x31,0x62,0x53,0xc4,0xf5,0xa6,0x97,0xb9,0x88,0xdb,0xea,0x7d,0x4c,0x1f,0x2e,
    0x43,0x72,0x21,0x10,0x87,0xb6,0xe5,0xd4,0xfa,0xcb,0x98,0xa9,0x3e,0x0f,0x5c,0x6d,
    0x86,0xb7,0xe4,0xd5,0x42,0x73,0x20,0x11,0x3f,0x0e,0x5d,0x6c,0xfb,0xca,0x99,0xa8,
    0xc5,0xf4,0xa7,0x96,0x01,0x30,0x63,0x52,0x7c,0x4d,0x1e,0x2f,0xb8,0x89,0xda,0xeb,
    0x3d,0x0c,0x5f,0x6e,0xf9,0xc8,0x9b,0xaa,0x84,0xb5,0xe6,0xd7,0x40,0x71,0x22,0x13,
    0x7e,0x4f,0x1c,0x2d,0xba,0x8b,0xd8,0xe9,0xc7,0xf6,0xa5,0x94,0x03,0x32,0x61,0x50,
    0xbb,0x8a,0xd9,0xe8,0x7f,0x4e,0x1d,0x2c,0x02,0x33,0x60,0x51,0xc6,0xf7,0xa4,0x95,
    0xf8,0xc9,0x9a,0xab,0x3c,0x0d,0x5e,0x6f,0x41,0x70,0x23,0x12,0x85,0xb4,0xe7,0xd6,
    0x7a,0x4b,0x18,0x29,0xbe,0x8f,0xdc,0xed,0xc3,0xf2,0xa1,0x90,0x07,0x36,0x65,0x54,
    0x39,0x08,0x5b,0x6a,0xfd,0xcc,0x9f,0xae,0x80,0xb1,0xe2,0xd3,0x44,0x75,0x26,0x17,
    0xfc,0xcd,0x9e,0xaf,0x38,0x09,0x5a,0x6b,0x45,0x74,0x27,0x16,0x81,0xb0,0xe3,0xd2,
    0xbf,0x8e,0xdd,0xec,0x7b,0x4a,0x19,0x28,0x06,0x37,0x64,0x55,0xc2,0xf3,0xa0,0x91,
    0x47,0x76,0x25,0x14,0x83,0xb2,0xe1,0xd0,0xfe,0xcf,0x9c,0xad,0x3a,0x0b,0x58,0x69,
    0x04,0x35,0x66,0x57,0xc0,0xf1,0xa2,0x93,0xbd,0x8c,0xdf,0xee,0x79,0x48,0x1b,0x2a,
    0xc1,0xf0,0xa3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1a,0x2b,0xbc,0x8d,0xde,0xef,
    0x82,0xb3,0xe0,0xd1,0x46,0x77,0x24,0x15,0x3b,0x0a,0x59,0x68,0xff,0xce,0x9d,0xac
};

//! /////////////////////////////////////////////////////////////////////////////////////////////////////////
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////
inline static void *ee_malloc(uint32_t size)
{
	return OSAL_Malloc(size);
}

inline static void ee_free(void *p)
{
	OSAL_Free(p);
}

inline static void ee_mutex_lock(void)
{
    Device_EnterCritical();
}

inline static void ee_mutex_unlock(void)
{
    Device_ExitCritical();
}

//读操作
inline static int ee_read_flash(uint32_t addr, uint8_t *data, uint32_t len)
{
	sf_read(HS_SF, 0, EE_FLASH_START_ADDR + addr, data, len);
	return 0;
}

//写操作
inline static int ee_write_flash(uint32_t addr, uint8_t *data, uint32_t len)
{
	sf_write(HS_SF, 0, EE_FLASH_START_ADDR + addr, data, len);
	return 0;
}

//擦除操作
inline static int ee_erase_sector(uint32_t addr)
{
	sf_erase(HS_SF, 0, EE_FLASH_START_ADDR + addr, 4*1024);
	return 0;
}

inline static uint8_t ee_calc_crc8(uint8_t *ptr, uint32_t len)
{
    uint8_t crc = 0xFF;

    while (len--)
    {
        crc = crc_table[crc ^ *ptr++];
    }
    return (crc);
}

//! /////////////////////////////////////////////////////////////////////////////////////////////////////////
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////

//判断数据是否全为0xFF
static int ee_check_data_0xff(uint8_t *p, uint32_t len)
{
	for (; len; len--)
	{
		if (*p++ != 0xFF)
		{
			return -1;
		}
	}
	return 0;
}

//检查一个块的校验字是否正常
static int ee_data_block_checkcrc(uint8_t *p_block)
{
	uint8_t check = ee_calc_crc8(p_block, EE_SECTOR_DATA_BLOCK_SIZE - 1);

	if (check != p_block[EE_SECTOR_DATA_BLOCK_SIZE - 1])
	{
		return -1;
	}
	return 0;
}

//根据一个物理扇区的内容，设置逻辑空间索引
static void ee_set_addr_index(uint16_t *logic_index, uint8_t *sector_data, uint8_t sector_addr)
{
	/* 从管理块的前一块开始往前搜索，搜索空闲数据块里面的最新有效块 */
	for (int i=EE_SECTOR_DATA_BLOCK_QTY*2-2; i>=EE_SECTOR_DATA_BLOCK_QTY; i--)
	{
		if (ee_data_block_checkcrc(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE]) == 0)
		{
			uint8_t addr = sector_data[(i + 1) * EE_SECTOR_DATA_BLOCK_SIZE - 2];

			if (addr >= EE_SECTOR_DATA_BLOCK_QTY)
			{
				ee_log("data block addr error");
				continue;
			}

			if (logic_index[addr] == 0xFFFF)
			{
				logic_index[addr] = sector_addr * (EE_SECTOR_DATA_BLOCK_QTY * 2) + i;
			}
		}
	}

	/* 剩下的直接与当前扇区的前64个数据块映射 */
	for (int i=0; i<EE_SECTOR_DATA_BLOCK_QTY; i++)
	{
		if (logic_index[i] == 0xFFFF)
		{
			logic_index[i] = sector_addr * (EE_SECTOR_DATA_BLOCK_QTY * 2) + i;
		}
	}
}

//建立逻辑空间索引
//logic_index：当前扇区对应映射的逻辑空间
//sector_data：当前扇区的数据
//sector_addr：当前扇区物理地址（0-8）
static void ee_create_index(uint16_t *logic_index, uint8_t *sector_data, uint8_t sector_addr)
{
	/* 当前扇区对应的逻辑空间已经与另一个扇区建立了映射关系 */
	if (*logic_index != 0xFFFF)
	{
		uint32_t erase_id1 = 0, erase_id2 = 0;
		
		/* 读取这个逻辑空间已经映射的物理扇区的擦写ID
		 * 根据任意块地址找到当前块所在扇区的管理块地址：*logic_index | 0x7F */
		ee_read_flash(((*logic_index) | 0x7F) * EE_SECTOR_DATA_BLOCK_SIZE, (uint8_t*)&erase_id1, sizeof(erase_id1));

		/* 读取当前扇区的擦写ID */
		memcpy(&erase_id2, &sector_data[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR], sizeof(erase_id2));

		/* 比较两个扇区的擦写ID，判断哪个扇区是最新数据 */
		if (erase_id2 > erase_id1)
		{
			/* 当前扇区ID大，说明当前扇区数据是最新
			 * 把这个逻辑空间已经映射的扇区标记为空闲扇区
			 * 重新让这个逻辑空间与当前扇区建立映射关系
			 */
			free_sector = *logic_index >> 7; //右移7：根据任意物理块地址算出扇区ID
			memset(logic_index, 0xFF, EE_SECTOR_DATA_BLOCK_QTY * 2);
			ee_set_addr_index(logic_index, sector_data, sector_addr);
		}
		else
		{
			/* 当前扇区ID小（失效扇区），标记为空闲 */
			free_sector = sector_addr;
		}
	}
	/* 当前扇区对应的逻辑空间未建立映射关系 */
	else
	{
		ee_set_addr_index(logic_index, sector_data, sector_addr);
	}
}

//第一次上电：重建EE
void ee_restore(void)
{
	int i;

	free_sector = 0xFF;
	for (i=0; i<EE_FLASH_SECTOR_QTY - 1; i++)
	{
		uint8_t admin_block[EE_SECTOR_DATA_BLOCK_SIZE] = {0};
		uint8_t temp[EE_SECTOR_DATA_BLOCK_SIZE] = {0};

		/* 擦除扇区 */
		if (ee_erase_sector(i * EE_FLASH_SECTOR_SIZE) != 0)
		{
			ee_log("ee_restore error");
			return;
		}

		/* 填充管理块数据 */
		admin_block[EE_SECTOR_DATA_BLOCK_SIZE - 2] = i;
		admin_block[EE_SECTOR_DATA_BLOCK_SIZE - 1] = ee_calc_crc8(admin_block, EE_SECTOR_DATA_BLOCK_SIZE - 1);

		/* 写管理块 */
		if (ee_write_flash(i * EE_FLASH_SECTOR_SIZE + EE_SECTOR_ADMIN_DATA_BLOCK_ADDR, admin_block, EE_SECTOR_DATA_BLOCK_SIZE) != 0)
		{
			ee_log("ee_restore error");
			return;
		}

		/* 读管理块 */
		if (ee_read_flash(i * EE_FLASH_SECTOR_SIZE + EE_SECTOR_ADMIN_DATA_BLOCK_ADDR, temp, EE_SECTOR_DATA_BLOCK_SIZE) != 0)
		{
			ee_log("ee_restore error");
			return;
		}

		/* 回读判断写入是否正确 */
		if (memcmp(admin_block, temp, EE_SECTOR_DATA_BLOCK_SIZE) != 0)
		{
			ee_log("ee_restore error");
			return;
		}

		/* 写addr_index */
		for (int j=0; j<EE_SECTOR_DATA_BLOCK_QTY; j++)
		{
			addr_index[i * EE_SECTOR_DATA_BLOCK_QTY + j] = i * EE_SECTOR_DATA_BLOCK_QTY * 2 + j;
		}
	}
	free_sector = i;
	ee_erase_sector(free_sector * EE_FLASH_SECTOR_SIZE);
}

//打印索引表
static void  ee_print_addr_index(void)
{
	if (debug_enable == 0)
	{
		return;
	}

	ee_log("addr_index:");
	for (int n=0; n<EE_FLASH_SECTOR_QTY-1; n++)
	{
		if (addr_index[n * EE_SECTOR_DATA_BLOCK_QTY] == 0xffff)
		{
			continue;
		}

		for (int m=0; m<EE_SECTOR_DATA_BLOCK_QTY; m++)
		{
			__ee_log("%04d ", addr_index[n * EE_SECTOR_DATA_BLOCK_QTY + m]);
			if (m == 31) __ee_log("\r\n");
		}
		__ee_log("\033[92m[logic block:%03d~%03d] \033[94m[sector:%d]\033[0m\r\n", n * EE_SECTOR_DATA_BLOCK_QTY, n * EE_SECTOR_DATA_BLOCK_QTY + EE_SECTOR_DATA_BLOCK_QTY -1, addr_index[n * EE_SECTOR_DATA_BLOCK_QTY] >> 7);
	}
}

//打印一个扇区数据
static void ee_print_sector_data(uint8_t *data, uint8_t sector_addr)
{
	if (debug_enable == 0)
	{
		return;
	}

	for (int j=0; j<EE_FLASH_SECTOR_SIZE; j++)
	{
		if ((j+2) % 32 == 0 && data[j] != 0xff)
		{
			__ee_log("\033[91m%02x \033[0m", data[j]); //当前块地址不为FF，说明写入了数据，就打印成红色
		}
		else
		{
			__ee_log("%02x ", data[j]);
		}
		
		if ((j+1) % 32 == 0)
		{
			__ee_log("\033[92m[%03d]\033[94m", j/32); //打印扇区内块地址
			__ee_log(" [%04d]\033[0m\r\n", sector_addr * EE_SECTOR_DATA_BLOCK_QTY * 2 + (j/32));//打印块地址（物理块地址）
		}
	}
	__ee_log("\r\n\r\n\r\n");
}

//EE初始化：成功返回0
int eeprom_init(void)
{
	uint8_t *buffer = (uint8_t *)ee_malloc(EE_FLASH_SECTOR_SIZE);
	
	if (buffer == NULL)
	{
		ee_log("malloc error");
		return -1;
	}
	
	/* 逻辑空间地址索引 */
	memset(addr_index, 0xFF, sizeof(addr_index));
	free_sector = 0xFF;
	
	ee_mutex_lock();
	for (int i=0; i<EE_FLASH_SECTOR_QTY; i++)
	{
		if (ee_read_flash(i * EE_FLASH_SECTOR_SIZE, buffer, EE_FLASH_SECTOR_SIZE) != 0)
		{
			ee_log("ee_read_flash error");
			free_sector = 0xFF;//标记为未初始化状态
			break;
		}

		/* 校验当前扇区的管理块 */
		if ( ee_data_block_checkcrc(&buffer[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR]) != 0 )
		{
			/* 当前扇区管理块校验错误 */
			ee_log("admin data block crc err:%d\r\n", i);
			if (free_sector == 0xFF)
			{
				free_sector = i;//当前扇区标记为空闲扇区
			}
			else
			{
				ee_log("ee_restore");
				ee_restore();//不止一个扇区错误，很可能第一次上电：重建EE
				break;
			}
		}
		else
		{
			/* 当前扇区管理块校验成功 */
			uint8_t sector_addr = buffer[EE_FLASH_SECTOR_SIZE-2];//获取当前扇区对应的逻辑扇区地址
			if (sector_addr < EE_FLASH_SECTOR_QTY - 1)
			{
				ee_create_index(&addr_index[sector_addr * EE_SECTOR_DATA_BLOCK_QTY], buffer, i);
			}
			else
			{
				ee_log("sector_addr error");
				free_sector = 0xFF;//标记为未初始化状态
				break; 
			}
		}

		ee_print_addr_index();
	}

	/* 擦除空闲扇区 */
	if (free_sector != 0xFF)
	{
		ee_read_flash(free_sector * EE_FLASH_SECTOR_SIZE, buffer, EE_FLASH_SECTOR_SIZE);
		if (ee_check_data_0xff(buffer, EE_FLASH_SECTOR_SIZE) != 0)
		{
			ee_erase_sector(free_sector * EE_FLASH_SECTOR_SIZE);
		}
	}
	ee_mutex_unlock();
	ee_free(buffer);
	__ee_log("free_sector:%d\r\n", free_sector);
	return (free_sector != 0xFF) ? 0 : -1;
}

//读EEPROM：成功返回0
int eeprom_read(uint32_t addr, uint8_t *data, uint32_t len)
{
	uint16_t block_addr, offset;
	//__ee_log("eeprom_read addr:%d len:%d\r\n",addr,len);
	if (free_sector == 0xFF)
	{
		return -1;// EE初始化失败
	}

	if (data == NULL || len < 1)
	{
		return -2;// 参数错误
	}

	if ((addr + len) > ((EE_FLASH_SECTOR_QTY - 1) * EE_SECTOR_DATA_BLOCK_QTY * (EE_SECTOR_DATA_BLOCK_SIZE - 2)))
	{
		return -3;// 地址超出EE最大范围
	}

	/* 计算逻辑块地址和偏移量（逻辑空间每个块30字节） */
	block_addr = addr / (EE_SECTOR_DATA_BLOCK_SIZE - 2);
	offset = addr % (EE_SECTOR_DATA_BLOCK_SIZE - 2);

	ee_mutex_lock();
	while (len)
	{
		uint16_t read_len = (EE_SECTOR_DATA_BLOCK_SIZE - 2) - offset;

		/* 分块读取 */
		read_len = (len < read_len) ? len : read_len;
		ee_read_flash(addr_index[block_addr] * EE_SECTOR_DATA_BLOCK_SIZE + offset, data, read_len);
		if (debug_enable)
		{
			ee_log("block:%03d->%04d   offset:%d   read_len:%d", block_addr, addr_index[block_addr], offset, read_len);
		}
		offset = 0;
		block_addr++;
		data += read_len;
		len -= read_len;
	}
	ee_mutex_unlock();
	return 0;
}

//查找空闲块，返回当前逻辑地址对应的扇区里面空闲的物理块地址
static uint16_t ee_find_free_block(uint16_t logic_block_addr, uint8_t *sector_data)
{
	int i;
	uint8_t block_addr = addr_index[logic_block_addr] % (EE_SECTOR_DATA_BLOCK_QTY * 2);//根据物理块地址算出扇区内块地址

	if (ee_check_data_0xff(&sector_data[block_addr * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE) == 0)
	{
		return addr_index[logic_block_addr];
	}

	for (i=(EE_SECTOR_DATA_BLOCK_QTY * 2 - 2); i>=EE_SECTOR_DATA_BLOCK_QTY; i--)
	{
		if (ee_check_data_0xff(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE) != 0)
		{
			break;//查找最后一个已占用的数据块
		}
	}

	if (i < (EE_SECTOR_DATA_BLOCK_QTY * 2 - 2))
	{
		//清掉低7位（& 0xFF80）：根据任意物理块地址找到该扇区的首个块地址
		return (addr_index[logic_block_addr] & 0xFF80) + i + 1;//最后那个已占用的数据块的下一个块就是空闲块
	}
	return 0xFFFF;
}

//核对当前扇区内的空闲块是否充足
static int ee_check_sector_free_block(uint8_t *sector_data, uint16_t block_addr, uint16_t offset, uint16_t len)
{
	uint16_t free_block_qty = 0, block_qty, sector_block_addr;
	int lenght, i;

	lenght = len;
	sector_block_addr = block_addr % EE_SECTOR_DATA_BLOCK_QTY;//逻辑块地址转换成扇区内块地址（0-63）

	for (i=sector_block_addr; (i < EE_SECTOR_DATA_BLOCK_QTY) && (lenght > 0); i++)
	{
		if (ee_check_data_0xff(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE) == 0)
		{
			free_block_qty++;//空闲块数量
		}

		lenght -= (EE_SECTOR_DATA_BLOCK_SIZE - 2) - offset;
		offset = 0;
	}
	block_qty = i - sector_block_addr;//需要在当前扇区写block_qty个数据块

	if (block_qty <= free_block_qty)
	{
		return 0;
	}

	for (i=(EE_SECTOR_DATA_BLOCK_QTY * 2 - 2); i>=EE_SECTOR_DATA_BLOCK_QTY; i--)
	{
		if (ee_check_data_0xff(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE) == 0)
		{
			if (++free_block_qty >= block_qty)
			{
				return 0;
			}
		}
		else
		{
			break;
		}
	}
	return -1;//当前扇区空闲块不够
}

//整理当前扇区的数据块，将新数据与当前扇区数据合并
static int ee_sector_data_merge(uint8_t *sector_data, uint8_t *data, uint16_t block_addr, uint16_t offset, uint16_t len)
{
	/* 整理当前扇区已有的数据 */
	for (int i=EE_SECTOR_DATA_BLOCK_QTY; i<(EE_SECTOR_DATA_BLOCK_QTY * 2 - 1); i++)
	{
		if (sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE + EE_SECTOR_DATA_BLOCK_SIZE - 2] != 0xFF)
		{
			if (ee_data_block_checkcrc(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE]) == 0)
			{
				uint8_t block = sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE + EE_SECTOR_DATA_BLOCK_SIZE - 2];

				memcpy(&sector_data[block * EE_SECTOR_DATA_BLOCK_SIZE], &sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE);
			}
		}
	}

	/* 清空空闲块区域 */
	memset(&sector_data[EE_SECTOR_DATA_BLOCK_QTY * EE_SECTOR_DATA_BLOCK_SIZE], 0xFF, (EE_SECTOR_DATA_BLOCK_QTY - 1) * EE_SECTOR_DATA_BLOCK_SIZE);
	
	/* 填充管理块数据*/
	*((uint32_t*)(&sector_data[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR])) = *((uint32_t*)(&sector_data[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR])) + 1;
	sector_data[EE_FLASH_SECTOR_SIZE - 1] = ee_calc_crc8(&sector_data[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR], EE_SECTOR_DATA_BLOCK_SIZE - 1);

	/* 填充要写入的数据 */
	uint16_t lenght = len;
	uint16_t sector_block_addr = block_addr % EE_SECTOR_DATA_BLOCK_QTY;//逻辑块地址转换成扇区内块地址（0-63）
	for (int i=sector_block_addr; (i < EE_SECTOR_DATA_BLOCK_QTY) && (lenght > 0); i++)
	{
		uint16_t write_len = (EE_SECTOR_DATA_BLOCK_SIZE - 2) - offset;

		write_len = (write_len < lenght) ? write_len : lenght;
		memcpy(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE + offset], data, write_len);
		sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE + EE_SECTOR_DATA_BLOCK_SIZE - 2] = i;
		sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE + EE_SECTOR_DATA_BLOCK_SIZE - 1] = ee_calc_crc8(&sector_data[i * EE_SECTOR_DATA_BLOCK_SIZE] ,EE_SECTOR_DATA_BLOCK_SIZE - 1);

		lenght -= write_len;
		data += write_len;
		offset = 0;
	}
	return len - lenght;
}

//写EEPROM：成功返回0（初始化时，必须擦掉空闲扇区）
int eeprom_write(uint32_t addr, uint8_t *data, uint32_t len)
{
	uint8_t *sector_data = NULL;
	uint32_t lenght = len;

	//__ee_log("eeprom_write addr:%d len:%d\r\n",addr,len);
	if (free_sector == 0xFF)
	{
		return -1; //EE初始化失败
	}

	if (data == NULL || len < 1)
	{
		return -2; //参数错误
	}

	if ((addr + len) > ((EE_FLASH_SECTOR_QTY - 1) * EE_SECTOR_DATA_BLOCK_QTY * (EE_SECTOR_DATA_BLOCK_SIZE - 2)))
	{
		return -3; //地址超出EE最大范围
	}

	if ((sector_data = (uint8_t *)ee_malloc(EE_FLASH_SECTOR_SIZE)) == NULL)
	{
		return -4; //memory error
	}
	
	ee_mutex_lock();
	while (lenght)
	{
		uint8_t temp[EE_SECTOR_DATA_BLOCK_SIZE] = {0};
		uint16_t sector_addr, free_block_addr, block_addr, offset, write_len;

		/* 计算逻辑块地址和块内偏移量（逻辑空间每个块30字节） */
		block_addr = addr / (EE_SECTOR_DATA_BLOCK_SIZE - 2);
		offset = addr % (EE_SECTOR_DATA_BLOCK_SIZE - 2);

		if ((lenght == len) || (block_addr % EE_SECTOR_DATA_BLOCK_QTY == 0))
		{
			/* 根据当前逻辑块对应的物理块地址算出扇区地址 */
			sector_addr = addr_index[block_addr] / (EE_SECTOR_DATA_BLOCK_QTY * 2);

			/* 读取整个扇区内容，判断当前扇区内空闲块数量是否足够 */
			ee_read_flash(sector_addr * EE_FLASH_SECTOR_SIZE, sector_data, EE_FLASH_SECTOR_SIZE);
			ee_print_sector_data(sector_data, sector_addr);
			if (ee_check_sector_free_block(sector_data, block_addr, offset, lenght) != 0)
			{
				/* 当前扇区空闲块不够，整个扇区迁移：需要写入的数据与原块数据整理合并到sector_data */
				ee_log("sector move -> [%d]\r\n", free_sector);
				write_len = ee_sector_data_merge(sector_data, data, block_addr, offset, lenght);
				ee_print_sector_data(sector_data, free_sector);
				
				/* 数据写入到空闲扇区 */
				ee_write_flash(free_sector * EE_FLASH_SECTOR_SIZE, sector_data, EE_SECTOR_DATA_BLOCK_SIZE * EE_SECTOR_DATA_BLOCK_QTY);
				ee_write_flash(free_sector * EE_FLASH_SECTOR_SIZE + EE_SECTOR_ADMIN_DATA_BLOCK_ADDR, &sector_data[EE_SECTOR_ADMIN_DATA_BLOCK_ADDR], EE_SECTOR_DATA_BLOCK_SIZE);

				/* 回读确认 */
				ee_read_flash(free_sector * EE_FLASH_SECTOR_SIZE + EE_SECTOR_ADMIN_DATA_BLOCK_ADDR, temp, EE_SECTOR_DATA_BLOCK_SIZE);
				if (ee_data_block_checkcrc(temp) != 0)
				{
					ee_log("write error");
					break;
				}

				/* 更新这个扇区对应的索引表 */
				for (int i=0; i<EE_SECTOR_DATA_BLOCK_QTY; i++)
				{
					//清掉低6位（& 0xFFC0）：根据任意逻辑块地址找到每个扇区对应的首块
					addr_index[(block_addr & 0xFFC0) + i] = free_sector * (EE_SECTOR_DATA_BLOCK_QTY * 2) + i;
				}

				/* 当前扇区标记为空闲并擦除 */
				free_sector = sector_addr;
				ee_erase_sector(free_sector * EE_FLASH_SECTOR_SIZE);
				ee_log("update free sector:%d\r\n", free_sector);
				
				offset = 0;
				addr += write_len;
				data += write_len;
				lenght -= write_len;
				continue;
			}
		}

		/* 分块写：计算当前这个数据块要写入的长度 */
		write_len = (EE_SECTOR_DATA_BLOCK_SIZE - 2) - offset;
		write_len = (lenght < write_len) ? lenght : write_len;

		/* 当前块没有写满：读取原数据块的数据与新数据进行合并 */
		if (write_len < (EE_SECTOR_DATA_BLOCK_SIZE - 2))
		{
			memcpy(temp, &sector_data[(addr_index[block_addr] % (EE_SECTOR_DATA_BLOCK_QTY * 2)) * EE_SECTOR_DATA_BLOCK_SIZE], EE_SECTOR_DATA_BLOCK_SIZE);
		}

		/* 查找一个空闲块写入数据 */
		free_block_addr = ee_find_free_block(block_addr, sector_data);
		if (debug_enable)
		{
			ee_log("free block: %d\r\n", free_block_addr);
		}
		if (free_block_addr == 0xFFFF)
		{
			ee_log("find free block error");
			break;
		}

		/* 合并新数据，写入对应的物理块 */
		memcpy(&temp[offset], data, write_len);
		temp[EE_SECTOR_DATA_BLOCK_SIZE - 2] = block_addr % EE_SECTOR_DATA_BLOCK_QTY; //扇区内块地址
		temp[EE_SECTOR_DATA_BLOCK_SIZE - 1] = ee_calc_crc8(temp, EE_SECTOR_DATA_BLOCK_SIZE - 1); //校验字
		memcpy(&sector_data[(free_block_addr % (EE_SECTOR_DATA_BLOCK_QTY * 2)) * EE_SECTOR_DATA_BLOCK_SIZE], temp, EE_SECTOR_DATA_BLOCK_SIZE);
		ee_print_sector_data(sector_data, sector_addr);
		ee_write_flash(free_block_addr * EE_SECTOR_DATA_BLOCK_SIZE, temp, EE_SECTOR_DATA_BLOCK_SIZE);

		/* 回读确认 */
		ee_read_flash(free_block_addr * EE_SECTOR_DATA_BLOCK_SIZE, temp, EE_SECTOR_DATA_BLOCK_SIZE);
		if (ee_data_block_checkcrc(temp) != 0)
		{
			ee_log("write error");
			break;
		}

		/* 更新索引 */
		addr_index[block_addr] = free_block_addr;

		offset = 0;
		addr += write_len;
		data += write_len;
		lenght -= write_len;
	}
	ee_mutex_unlock();
	ee_free(sector_data);
	ee_print_addr_index();
	return ((lenght != 0) ? -5 : 0);
}
